using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GameAOT;
using LFloatMath.Math;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class UIBattlePad : UIEntityWindow
    {
        /// <summary>
        ///     静态配置
        /// </summary>
        private static UICreateConfig _createConfig = new()
        {
            prefabName = nameof(UIBattlePad),
            parentPath = "Battle",
            layer = EUILayer.Normal,
        };

        public override IUICreateConfig createConfig => _createConfig;

        protected UIB_UIBattlePad ui { get; set; }
        private UIMsgDispatcher currMsgDispatcher => this._msgDispatcher as UIMsgDispatcher;

        #region Template Generate,don't modify

        protected partial class UIB_UIBattlePad
        {
            #region ObjectBinding Generate

            public UnityEngine.RectTransform hUD { protected set; get; }
            public IQIGame.Onigao.Framework.ExText round { protected set; get; }
            public UnityEngine.GameObject hpPrefab { protected set; get; }
            public UnityEngine.RectTransform orderLayout { protected set; get; }
            public UnityEngine.GameObject orderItem { protected set; get; }
            public IQIGame.Onigao.Framework.ExRawImage videoPlayer { protected set; get; }
            public UnityEngine.GameObject staticPanel { protected set; get; }
            public UnityEngine.GameObject dynamicPanel { protected set; get; }
            public UnityEngine.GameObject uIHeroHeadItem { protected set; get; }
            public IQIGame.Onigao.Framework.ExButton skip { protected set; get; }
            public IQIGame.Onigao.Framework.ExButton accelerate { protected set; get; }
            public IQIGame.Onigao.Framework.ExImage activing_Icon_Head { protected set; get; }
            public IQIGame.Onigao.Framework.ExText textName { protected set; get; }
            public IQIGame.Onigao.Framework.ExButton auto { protected set; get; }
            public UnityEngine.GameObject panel { protected set; get; }
            public IQIGame.Onigao.Framework.ExImage accelerateImg { protected set; get; }
            public IQIGame.Onigao.Framework.ExImage autoImg { protected set; get; }

            public virtual void InitBinding(ObjectBinding __binding)
            {
                __binding.TryGetVariableValue<UnityEngine.RectTransform>("hUD", out var __tbv0);
                this.hUD = __tbv0;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExText>("round", out var __tbv1);
                this.round = __tbv1;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("hpPrefab", out var __tbv2);
                this.hpPrefab = __tbv2;
                __binding.TryGetVariableValue<UnityEngine.RectTransform>("orderLayout", out var __tbv3);
                this.orderLayout = __tbv3;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("orderItem", out var __tbv4);
                this.orderItem = __tbv4;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExRawImage>("videoPlayer", out var __tbv5);
                this.videoPlayer = __tbv5;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("staticPanel", out var __tbv6);
                this.staticPanel = __tbv6;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("dynamicPanel", out var __tbv7);
                this.dynamicPanel = __tbv7;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("uIHeroHeadItem", out var __tbv8);
                this.uIHeroHeadItem = __tbv8;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExButton>("skip", out var __tbv9);
                this.skip = __tbv9;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExButton>("accelerate", out var __tbv10);
                this.accelerate = __tbv10;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExImage>("activing_Icon_Head", out var __tbv11);
                this.activing_Icon_Head = __tbv11;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExText>("textName", out var __tbv12);
                this.textName = __tbv12;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExButton>("auto", out var __tbv13);
                this.auto = __tbv13;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("panel", out var __tbv14);
                this.panel = __tbv14;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExImage>("accelerateImg", out var __tbv15);
                this.accelerateImg = __tbv15;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExImage>("autoImg", out var __tbv16);
                this.autoImg = __tbv16;
            }

            #endregion ObjectBinding Generate
        }

        #endregion Template Generate,don't modify

        /// <summary>
        ///     可以自定义修改的
        /// </summary>
        protected partial class UIB_UIBattlePad
        {
            public virtual void StartBinding(GameObject __go)
            {
                var binding = __go.GetComponent<ObjectBinding>();
                if (binding != null)
                {
                    this.InitBinding(binding);
                }
            }
        }

        private UIItemPool<UIBattleOrderItem> mOrderPool;
        private List<UIBattleOrderItem> orders = new List<UIBattleOrderItem>();

        private UIItemPool<UIHpPrefabItem> mHpPool;
        private Dictionary<UnitView, UIHpPrefabItem> hpMap = new Dictionary<UnitView, UIHpPrefabItem>();

        private UIItemPool<UIHeroHeadItem> mHeadPool;
        private Dictionary<UnitView, UIHeroHeadItem> headMap = new Dictionary<UnitView, UIHeroHeadItem>();

        private BetterLinkedList<HUDNumInitParam> hudQueue = new BetterLinkedList<HUDNumInitParam>();

        private const string AtlasName = "UIBattle";

        protected override void OnInit()
        {
            this.ui.orderItem.SetActive(false);
            this.mOrderPool = this.InitPool<UIBattleOrderItem>(this.ui.orderItem);
            this.ui.hpPrefab.SetActive(false);
            this.mHpPool = this.InitPool<UIHpPrefabItem>(this.ui.hpPrefab);
            this.ui.uIHeroHeadItem.SetActive(false);
            this.mHeadPool = this.InitPool<UIHeroHeadItem>(this.ui.uIHeroHeadItem);
            var rData = BattleManager.Instance.ctrl.data;
            for (int i = 0; i < rData.units.Count; i++)
            {
                var rUnit = rData.units[i];
                this.SyncHp(rUnit);
            }

            this.ui.skip.AddClickEvent(this.OnBtnSkip_Clicked);
            this.ui.accelerate.AddClickEvent(this.OnBtnAccelerate_Clicked);
            this.ui.auto.AddClickEvent(this.OnAutoClicked);

            this.isUpdate = true;
            this.isLateUpdate = true;
        }

        protected override void BeforeInit()
        {
            ui = new UIB_UIBattlePad();
            ui.StartBinding(gameObject);
        }

        protected override void OnShow(UIBaseData data)
        {

        }

        protected override void OnHide()
        {

        }

        protected override void AddMsgListeners()
        {
            base.AddMsgListeners();
            this.currMsgDispatcher.AddListener<DamageResponse>(MsgEventType.BattleView_TakeDamage, this.OnDamage);
            this.currMsgDispatcher.AddListener<CureResponse>(MsgEventType.BattleView_TakeCure, this.OnCure);
            this.currMsgDispatcher.AddListener<UnitView, EAttributeType>(MsgEventType.BattleView_AttrChnage, this.OnAttrChange);
            this.currMsgDispatcher.AddListener<int>(MsgEventType.BattleView_Round, this.OnRoundChange);
            this.currMsgDispatcher.AddListener(MsgEventType.BattleView_TurnQueueChange, this.OnQueueChange);
            this.currMsgDispatcher.AddListener<UnitView>(MsgEventType.BattleView_UnitRemove, this.OnUnitRemove);
            this.currMsgDispatcher.AddListener<UnitView>(MsgEventType.BattleView_UnitAdd, this.SyncHp);
            this.currMsgDispatcher.AddListener<UnitView>(MsgEventType.BattleView_Shield, this.SyncHp);
            this.currMsgDispatcher.AddListener<UnitView>(MsgEventType.BattleView_WeaknessPoint, this.OnWeaknessPoint);
            this.currMsgDispatcher.AddListener<UnitView>(MsgEventType.BattleView_Buff, this.SyncBuff);
            this.currMsgDispatcher.AddListener<UnitView, bool>(MsgEventType.BattleView_UnitActive, this.OnUnitActive);
        }

        protected override void OnDispose()
        {
            if (this._curAccelerateGuid > 0)
            {
                TimeScaleManager.Instance.RemoveTimeScale(this._curAccelerateGuid);
            }
        }

        private Dictionary<Vector3, int> hudNumFrame = new Dictionary<Vector3, int>();
        private float hudShowSpace;

        protected override void OnUpdate(float dt, float unscaledDt)
        {
            int nMaxShowCount = 1;
            if (this.hudQueue.Count > 0)
            {
                if (this.hudShowSpace >= 0 && this.hudShowSpace < HUDGlobal.numTimeSpace)
                {
                    this.hudShowSpace += dt;
                    return;
                }
                this.hudShowSpace = 0;
                this.hudNumFrame.Clear();
                var rNode = this.hudQueue.FirstNode;
                while (rNode != null)
                {
                    var rNumParam = rNode.value;
                    var rNextNode = rNode.next;
                    if (!this.hudNumFrame.TryGetValue(rNumParam.worldPos, out var nCount))
                    {
                        this.hudNumFrame[rNumParam.worldPos] = 1;
                    }
                    else
                    {
                        this.hudNumFrame[rNumParam.worldPos]++;
                    }
                    // 进行到有一个满了
                    if (this.hudNumFrame[rNumParam.worldPos] <= nMaxShowCount)
                    {
                        HUDNumberRender.Instance.AddHudNumber(rNumParam.worldPos, rNumParam.worldDir, (int)rNumParam.hudType, rNumParam.number, rNumParam.color, rNumParam.scale);
                        this.hudQueue.RemoveNode(rNode);
                    }
                    rNode = rNextNode;
                }
            }
            else
            {
                this.hudShowSpace = -1;
            }
        }

        protected override void OnLateUpdate()
        {
            foreach (var rPair in this.hpMap)
            {
                var rUnit = rPair.Key;
                rPair.Value.SyncPos(rUnit, this.ui.hUD);
            }
        }

        public void ShowPanel()
        {
            this.ui.panel.SetActive(true);
        }

        public void HidePanel()
        {
            this.ui.panel.SetActive(false);
        }

        private UIHpPrefabItem CreateHpBar(UnitView unit)
        {
            if (unit.unitType == EUnitType.Totem)
            {
                return null;
            }
            var rItem = this.mHpPool.GetOne();
            rItem.Initialize(unit.teamIndex, unit.weaknessTypeList);
            this.hpMap.TryAdd(unit, rItem);
            return rItem;
        }

        private UIHeroHeadItem CreateHead(UnitView unit)
        {
            if (unit.unitType == EUnitType.Totem)
            {
                return null;
            }
            var rItem = this.mHeadPool.GetOne();
            rItem.Initialize(unit.configID, unit.lv, unit.skinID);
            rItem.Refresh(unit);
            this.headMap.TryAdd(unit, rItem);
            return rItem;
        }

        public void RefreshHeroHead(UnitView rUnit)
        {
            if (this.headMap.TryGetValue(rUnit, out var rHead))
            {
                rHead.Refresh(rUnit);
            }
        }

        private void AddHudNumber(Vector3 worldPos, Vector3 worldDir, EHUDNumberRenderType hudType, int number, Color color, float scale = 1f)
        {
            var rInitParam = new HUDNumInitParam()
            {
                hudType = hudType,
                number = number,
                worldPos = worldPos,
                worldDir = worldDir,
                color = color,
                scale = scale
            };
            this.hudQueue.AddLast(rInitParam);
        }

        #region Event

        private void SyncHp(UnitView rUnit)
        {
            if (!this.hpMap.TryGetValue(rUnit, out var rHpBar))
            {
                rHpBar = this.CreateHpBar(rUnit);
            }
            if (rHpBar == null)
            {
                return;
            }
            var rAttrComp = rUnit.GetComponent<AttributeViewComponent>(ETComponentType.AttributeViewComponent);
            var nHp = rAttrComp.Get(EAttributeType.Hp);
            var nMaxHp = rAttrComp.Get(EAttributeType.MaxHp);
            rHpBar.SetHp((nHp / nMaxHp).ToFloat());

            if (rUnit.teamIndex == BattleConst.TeamRedIndex)
            {
                if (!this.headMap.TryGetValue(rUnit, out var rHead))
                {
                    rHead = this.CreateHead(rUnit);
                }
                if (rHead == null)
                {
                    return;
                }
                var rBuffComp = rUnit.GetComponent<BuffViewComponent>(ETComponentType.BuffViewComponent);
                rHead.SetHp(nHp, nMaxHp, rBuffComp.shield.ToLFloat());
                rHead.SetSp(rAttrComp.Get(EAttributeType.SP), rAttrComp.Get(EAttributeType.MaxSP));
            }
        }

        private void SyncBuff(UnitView unit)
        {
            if (!this.hpMap.TryGetValue(unit, out var rHpBar))
            {
                rHpBar = this.CreateHpBar(unit);
            }

            var rBuffComp = unit.GetComponent<BuffViewComponent>(ETComponentType.BuffViewComponent);
            if (unit.teamIndex == BattleConst.TeamRedIndex)
            {
                if (!this.headMap.TryGetValue(unit, out var rHead))
                {
                    rHead = this.CreateHead(unit);
                }
                rHead?.SyncBuff(rBuffComp.buffs);
            }
        }

        private void OnDamage(DamageResponse rDamage)
        {
            if (rDamage.finalDamage <= 0)
            {
                return;
            }
            var rUnit = BattleManager.Instance.ctrl.data.GetUnit(rDamage.defender);
            if (rUnit == null)
            {
                return;
            }

            var rViewComp = rUnit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            var rNumType = rUnit.teamIndex == BattleConst.TeamBlueIndex ? EHUDNumberRenderType.NormalHurt : EHUDNumberRenderType.SelfHurt;
            this.AddHudNumber(rViewComp.position, Vector3.up * 2, rNumType, rDamage.finalDamage, Color.white);
        }

        private void OnCure(CureResponse rCure)
        {
            if (rCure.finalCure <= 0)
            {
                return;
            }
            var rData = BattleManager.Instance.ctrl.data;
            var rUnit = rData.GetUnit(rCure.defender);
            if (rUnit == null)
            {
                return;
            }
            var rViewComp = rUnit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            var rNumType = EHUDNumberRenderType.Cure;
            this.AddHudNumber(rViewComp.position, Vector3.up * 2, rNumType, rCure.finalCure, Color.green);
        }

        private void OnAttrChange(UnitView rUnit, EAttributeType rType)
        {
            if (rType == EAttributeType.Hp || rType == EAttributeType.SP)
            {
                this.SyncHp(rUnit);
            }
        }

        private void OnRoundChange(int nRoundNum)
        {
            this.ui.round.text = nRoundNum.ToString();
            foreach (var rPair in this.headMap)
            {
                rPair.Value.Refresh(rPair.Key);
            }
        }

        private void OnQueueChange()
        {
            var rCtrl = BattleManager.Instance.ctrl.turnCtrl;
            var rOrders = ListPool<UnitView>.Get();
            if (rCtrl.current != null)
            {
                rOrders.Add(rCtrl.current);
            }

            rOrders.AddRange(rCtrl.afterQueue);
            rOrders.Reverse(); // 从右向左排
            var nOrderCount = rOrders.Count;
            while (this.orders.Count > nOrderCount)
            {
                var nIndex = this.orders.Count - 1;
                var rOrder = this.orders[nIndex];
                this.orders.RemoveAt(nIndex);
                this.mOrderPool.HideOne(rOrder);
            }

            while (this.orders.Count < nOrderCount)
            {
                var rOrder = this.mOrderPool.GetOne();
                this.orders.Add(rOrder);
            }

            for (int i = 0; i < nOrderCount; i++)
            {
                var rOrderUnit = rOrders[i];
                var iconAssetPath = rOrderUnit.battleHeadIconPath; // PathConstant.GetHeadPath(rOrderUnit.battleHeadIconPath);
                var rIcon = this.resLoader.LoadABAsset<Sprite>(iconAssetPath);
                this.orders[i].SetItem(rOrderUnit.GUID, rIcon, rOrderUnit.teamIndex == BattleConst.TeamBlueIndex);
            }

            if (nOrderCount > 0)
            {
                var rCurUnit = rOrders[^1];
                var iconAssetPath = rCurUnit.battleHeadIconPath;
                this.ui.activing_Icon_Head.sprite = this.resLoader.LoadABAsset<Sprite>(iconAssetPath);
                this.ui.textName.text = rCurUnit.name;

                foreach (var rPair in this.headMap)
                {
                    rPair.Value.OnTurn(rCurUnit);
                }
            }
        }

        private void OnUnitRemove(UnitView unit)
        {
            if (this.hpMap.TryGetValue(unit, out var rItem))
            {
                this.mHpPool.HideOne(rItem);
                this.hpMap.Remove(unit);
            }
        }

        private void OnWeaknessPoint(UnitView rUnit)
        {
            if (!this.hpMap.TryGetValue(rUnit, out var rHpBar))
            {
                rHpBar = this.CreateHpBar(rUnit);
            }
            rHpBar?.SetWeaknessPoint(rUnit.weaknessPoint);
        }

        private void OnUnitActive(UnitView unit, bool active)
        {
            if (!this.hpMap.TryGetValue(unit, out var rHpBar))
            {
                rHpBar = this.CreateHpBar(unit);
            }
            rHpBar?.Active(active);
        }

        #endregion

        #region Button

        private void OnBtnSkip_Clicked()
        {
            // StoryManager.Instance.StartPlayStoryById(12100100, 0, null).Forget();

            BattleManager.Instance.Skip();
        }

        private int _curAccelerateGuid = -1;

        private void OnBtnAccelerate_Clicked()
        {
            if (this._curAccelerateGuid <= 0)
            {
                this._curAccelerateGuid = TimeScaleManager.Instance.AddTimeScale(1.5f, ETimeScaleType.BattleAcc);
                this.SetImageSprite(this.ui.accelerateImg, PathConstant.GetAtlasSpritePath(AtlasName, "BattleUI_DoubleSpeed_2"));
            }
            else
            {
                TimeScaleManager.Instance.RemoveTimeScale(this._curAccelerateGuid);
                this._curAccelerateGuid = -1;
                this.SetImageSprite(this.ui.accelerateImg, PathConstant.GetAtlasSpritePath(AtlasName, "BattleUI_DoubleSpeed_1"));
            }
        }

        private void OnAutoClicked()
        {
            this.ChangeAutoBattle().Forget();
        }

        #endregion

        private async UniTaskVoid ChangeAutoBattle()
        {
            var bCurAuto = BattleManager.Instance.ctrl.data.autoBattle;
            bool bAuto = await BattleManager.Instance.AutoBattle(!bCurAuto);
            var rAutoImgPath = PathConstant.GetAtlasSpritePath(AtlasName, "BattleUI_Auto_1");
            if (bAuto)
            {
                rAutoImgPath = PathConstant.GetAtlasSpritePath(AtlasName, "BattleUI_Auto_2");
            }
            this.SetImageSprite(this.ui.autoImg, rAutoImgPath);
        }

        struct HUDNumInitParam
        {
            public Vector3 worldPos;
            public Vector3 worldDir;
            public EHUDNumberRenderType hudType;
            public int number;
            public Color color;
            public float scale;
        }
    }
}